package com.pucong.gitee.database.backup.configuration.swagger;

import com.fasterxml.classmate.ResolvedType;
import com.google.common.base.Optional;
import com.pucong.gitee.database.backup.common.selfenum.CommonEnum;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import springfox.documentation.builders.ModelPropertyBuilder;
import springfox.documentation.schema.Annotations;
import springfox.documentation.service.AllowableListValues;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;
import springfox.documentation.swagger.schema.ApiModelProperties;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * swagger 显示枚举类转换
 * @author pucong
 * @date 2017-05-23
 */
@Component
@Slf4j
public class CodedEnumPropertyPlugin implements ModelPropertyBuilderPlugin {
    @Override
    public void apply(ModelPropertyContext context) {
        Optional<ApiModelProperty> annotation = Optional.absent();

        if (context.getAnnotatedElement().isPresent()) {
            annotation = annotation.or(ApiModelProperties.findApiModePropertyAnnotation(context.getAnnotatedElement().get()));
        }
        if (context.getBeanPropertyDefinition().isPresent()) {
            annotation = annotation.or(Annotations.findPropertyAnnotation(
                    context.getBeanPropertyDefinition().get(),
                    ApiModelProperty.class));
        }
        final Class<?> rawPrimaryType = context.getBeanPropertyDefinition().get().getRawPrimaryType();
        //过滤得到目标类型
        if (annotation.isPresent() && CommonEnum.class.isAssignableFrom(rawPrimaryType)) {
            //获取CodedEnum的code值
            CommonEnum[] values = (CommonEnum[]) rawPrimaryType.getEnumConstants();
            final List<String> displayValues = Arrays.stream(values).map(codedEnum -> codedEnum.getValue().toString()).collect(Collectors.toList());
            final AllowableListValues allowableListValues = new AllowableListValues(displayValues, rawPrimaryType.getTypeName());
            //固定设置为int类型
            final ResolvedType resolvedType = context.getResolver().resolve(int.class);
            ModelPropertyBuilder builder = context.getBuilder();
            builder.allowableValues(allowableListValues).type(resolvedType);

            final List<String> descriptions = Arrays.stream(values).map(codedEnum -> codedEnum.getName() + ":" +codedEnum.getValue()).collect(Collectors.toList());
            String description = getDescription(builder);
            builder.description(description + ":" +descriptions.toString());
        }
    }

    private String getDescription(ModelPropertyBuilder builder){
        Class<ModelPropertyBuilder> modelPropertyBuilderClass = ModelPropertyBuilder.class;
        Field[] fields = ModelPropertyBuilder.class.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            if("description".equals(fields[i].getName())){
                fields[i].setAccessible(true);
                try {
                    return fields[i].get(builder).toString();
                } catch (Exception e) {
                    log.error("反射获取值失败");
                }
            }
        }
        return "";
    }

    @Override
    public boolean supports(DocumentationType documentationType) {
        return true;
    }
}
